package com.engine.salary.entity.salarysob.bo;

import com.engine.salary.common.LocalDateRange;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.enums.SalaryCycleTypeEnum;
import com.engine.salary.util.SalaryDateUtil;

import java.time.*;
import java.util.Date;
import java.util.Objects;

/**
 * 薪资账套的薪资周期、税款所属期、考勤周期、福利台账月份
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalarySobCycleBO {

    /**
     * 根据薪资所属月计算出薪资账套的薪资周期、税款所属期、考勤周期、福利台账月份
     *
     * @param salarySob   薪资账套
     * @param salaryMonth 薪资所属月
     * @return
     */
    public static SalarySobCycleDTO buildSalarySobCycle(SalarySobPO salarySob, YearMonth salaryMonth) {
        if (salarySob == null) {
            return null;
        }

        SalarySobCycleDTO salarySobCycleDTO = SalarySobCycleDTO.builder()
                .salarySobId(salarySob.getId())
                .salaryMonth(salaryMonth)
                .taxCycle(buildCycle(salaryMonth, salarySob.getTaxCycleType()))
                .socialSecurityCycle(buildCycle(salaryMonth, salarySob.getSocialSecurityCycleType()))
                .salaryCycle(buildCycleDateRange(salaryMonth, salarySob.getSalaryCycleType(), salarySob.getSalaryCycleFromDay()))
                .attendCycle(buildCycleDateRange(salaryMonth, salarySob.getAttendCycleType(), salarySob.getAttendCycleFromDay()))
                .build();

        salarySobCycleDTO.setSalaryDate(SalaryDateUtil.toDate(salarySobCycleDTO.getSalaryMonth(), 1));
        salarySobCycleDTO.setTaxDate(SalaryDateUtil.toDate(salarySobCycleDTO.getTaxCycle(), 1));
        salarySobCycleDTO.setSocialSecurityDate(SalaryDateUtil.toDate(salarySobCycleDTO.getSocialSecurityCycle(), 1));
        LocalDateRange salaryCycle = salarySobCycleDTO.getSalaryCycle();
        salarySobCycleDTO.setSalaryCycleFromDate(salaryCycle.getFromDate());
        salarySobCycleDTO.setSalaryCycleEndDate(salaryCycle.getEndDate());
        LocalDateRange attendCycle = salarySobCycleDTO.getAttendCycle();
        salarySobCycleDTO.setAttendCycleFromDate(attendCycle.getFromDate());
        salarySobCycleDTO.setAttendCycleEndDate(attendCycle.getEndDate());

        return salarySobCycleDTO;
    }

    /**
     * 根据薪资所属月、薪资账套所设置的税款所属期（或福利台账月份）计算出税款所属期、福利台账的具体月份
     *
     * @param salaryMonth 薪资所属月
     * @param cycleType   薪资账套所设置的税款所属期（或福利台账月份）
     * @return
     */
    private static YearMonth buildCycle(YearMonth salaryMonth, Integer cycleType) {
        if (Objects.equals(cycleType, SalaryCycleTypeEnum.BEFORE_LAST_MONTH.getValue())) {
            return salaryMonth.plus(Period.ofMonths(-2));
        }
        if (Objects.equals(cycleType, SalaryCycleTypeEnum.LAST_MONTH.getValue())) {
            return salaryMonth.plus(Period.ofMonths(-1));
        }
        if (Objects.equals(cycleType, SalaryCycleTypeEnum.THIS_MONTH.getValue())) {
            return salaryMonth;
        }
        if (Objects.equals(cycleType, SalaryCycleTypeEnum.NEXT_MONTH.getValue())) {
            return salaryMonth.plus(Period.ofMonths(1));
        }
        return YearMonth.parse("2000-01");
    }

    /**
     * 根据薪资所属月、薪资账套所设置的薪资周期（或考勤周期）、薪资周期起始日（活考勤周期起始日）计算出薪资账套的薪资周期、考勤周期的具体日期范围
     *
     * @param salaryMonth 薪资所属月
     * @param cycleType   薪资账套所设置的薪资周期（或考勤周期）
     * @param fromDay     薪资账套所设置的薪资周期起始日（或考勤周期起始日）
     * @return
     */
    private static LocalDateRange buildCycleDateRange(YearMonth salaryMonth, Integer cycleType, Integer fromDay) {
        YearMonth result = buildCycle(salaryMonth, cycleType);
        if (result == null) {
            return null;
        }
        ZoneId zone = ZoneId.systemDefault();
        LocalDate fromDate = result.atEndOfMonth();
        if (fromDate.getDayOfMonth() > fromDay) {
            fromDate = result.atDay(fromDay);
        }
        Instant fromInstant = fromDate.atStartOfDay().atZone(zone).toInstant();

        LocalDate endDate = fromDate.plusMonths(1).plusDays(-1);
        Instant endInstant = endDate.atStartOfDay().atZone(zone).toInstant();


        return LocalDateRange.builder()
                .fromDate(Date.from(fromInstant))
                .endDate(Date.from(endInstant))
                .build();
    }
}
